/* 
  File: signal-handler.c
  Author: Anthony R. Cassandra
  July, 1998

  *****
  Copyright 1994-1997, Brown University
  Copyright 1998, Anthony R. Cassandra

                           All Rights Reserved
                           
  Permission to use, copy, modify, and distribute this software and its
  documentation for any purpose other than its incorporation into a
  commercial product is hereby granted without fee, provided that the
  above copyright notice appear in all copies and that both that
  copyright notice and this permission notice appear in supporting
  documentation.
  
  ANTHONY CASSANDRA DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
  INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ANY
  PARTICULAR PURPOSE.  IN NO EVENT SHALL ANTHONY CASSANDRA BE LIABLE FOR
  ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  *****

  Routines having to do with signal handling.  There are three that we
  are interested in: 

  SIGINT - A CTRL-C in the terminal window will cause a flag to be set
  so that after the current iteration, the algorithm will terminate
  normally.

  SIGVTALRM - Caused by a preset timer when an upper bound on the
  excution time is given.  This is used to ensure the algorithm does
  not exceed a certain time limit.  Note that the actual stopping time
  is normally larger than the peset time as it can take some time to
  notice and react to this signal.

  SIGSEGV - Many things can cause this, but there is one in particular
  that we are concerned about: resource limitations exceeded.  A
  command line option allows you to put an upper limit on the memory
  this process will use.  When the upper limit is exceeded this signal
  is generated.
*/
#define SIGNAL_HANDLER_C

#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>

/*
Can remove these???? 

#include <sys/types.h>
#include <unistd.h>
#include <limits.h>
*/

/* This has : signal() */
#include <signal.h>

/* This has: setitimer(), 'struct itimerval' */
#include <sys/time.h>

/* This has: 'struct rlimit', setrlimit() */
#include <sys/resource.h>

//#include <mdp.h>

//#include "global.h"
//#include "timing.h"
//#include "params.h"
#include "signal-handler.h"

/* Defining this constant turns off the memory limit stuff */
#define DISABLE_MEMORY_LIMIT

/* Flag is set if the SIGINT signal has been received. The SIGINT is
   generated by CRTL-C and the program will terminate after the
   current epoch is copleted. This give a more graceful shut-down,
   since the behavior mimics what it would have done if a finite
   horizon for the current horizon was selected. */
bool gInterrupt = false;

/* We will want to do some reporting of information when certina
   interrupts occur.  Thus, we need to maintain a pointer to the
   current parameter structure being used.  This pointer should be set
   prior to seting up the signal handlers for a particular parameter
   setting. */
//PomdpSolveParams gInterruptParamContext = NULL;

/**********************************************************************/
//  void reportSIGSEGV( PomdpSolveParams param  ) {
//    double stop_time_user, stop_time_system;
//    double time = -1.0;

//    if ( param->stat != NULL ) {

//      getSecsDetail( &stop_time_user, &stop_time_system );

//      time = stop_time_user + stop_time_system
//        - param->stat->start_time_user 
//        - param->stat->start_time_system;

//    } /* if keeping stats. 

//    if ( param->succinct != TRUE ) {
    
//      fprintf( param->report_file,
//               "\nTerminated due to SIGSEGV signal after %.3lf secs.\n", 
//               time );
   
//      fprintf( param->report_file,
//               "\tPossibly due to memory limit of %d bytes.\n",
//               param->memory_limit );
    
//    }  /* if gSuccinct != TRUE
  
//    else
//      fprintf( param->report_file, "T=>%.3lf(SIGSEGV) ", time );
  
//    reportContextDetails( param->stat );

//    if ( param->succinct == TRUE )
//      fprintf( param->report_file, "\n" );

//  }  /* reportSIGSEGV
//  /**********************************************************************/
//  void reportSIGVTALRM( PomdpSolveParams param  ) {
//  /*
//    Takes the current parameter context when the SIGSEGV signal is
//    received and gives a reporting of the current status.
//  */
//     double stop_time_user, stop_time_system;
//     double time = -1.0;
//     int a;

//     /* Declared in enum.c
//     extern int gNumVectorsEnum;

//     /* Declared in linear-support.c
//     extern int gNumVertices;

//    if ( param->stat != NULL ) {

//      getSecsDetail( &stop_time_user, &stop_time_system );

//      time = stop_time_user + stop_time_system
//        - param->stat->start_time_user 
//        - param->stat->start_time_system;

//    } /* if keeping stats.
      
//     if ( param->succinct == TRUE ) {

//       switch ( param->method ) {
//       case Witness:
//       case IncrementalPruning:
//       case TwoPass:
//         for ( a = 0; a < gNumActions; a++ )
//           fprintf( param->report_file, "Q%d=0 ", a);
//         break;
       
//       case LinearSupport:
//         fprintf( param->report_file, "VertEnum=%d ", gNumVertices );
//         break;
       
//       case Enumeration:
//         fprintf( param->report_file,
//                  "VectEnum=%d ", gNumVectorsEnum );
//         break;
       
//          default:
//            break;
//       }  /* switch
     
//       /* Now print the time.
//       fprintf( param->report_file, "V=0 T=>%.3lf ", time );

//     }  /* if gSuccinct
   
//     else {
//       fprintf(param->report_file, 
//               "\nTerminated due to SIGVTALRM signal after %.3lf secs.\n", 
//               time );
     
//     }
   
//     reportContextDetails( param->stat );
//     if ( param->succinct == TRUE )
//       fprintf(param->report_file, "\n" );

//  } /* reportSIGVTALRM
//  /**********************************************************************/
//  static void signalHandlerSIGSEGV( int sig ) {
//  */
//     If we get the SIGSEGV, then one possibility is that we have
//     exceeded the preset memory limit of the program.  In this case,
//     we give minimal timing information.
//  */
  
//    Assert( gInterruptParamContext != NULL,
//            "SIGSEGV received, but no parameter context was set." );

//    reportSIGSEGV( gInterruptParamContext );
  
//    exit ( 0 );

//  }  /* signalHandlerSIGSEGV
//  /**********************************************************************/
//  static void signalHandlerSIGVTALRM( int sig ) {
//  */
//     If we get the SIGVTALRM signal, then that means that the timer 
//     we set went off.  In this case the program halts immediately and
//     outputs stuff that indicates it aborted.
//  */

//    Assert( gInterruptParamContext != NULL,
//            "SIGVTALRM received, but no parameter context was set." );

//    reportSIGVTALRM( gInterruptParamContext );
   
//}  /* signalHandlerSIGVTALRM
///**********************************************************************/
static void signalHandlerSIGINT( int sig ) {
/* 
   If SIGINT (CTRL-C) is sent to the program in the middle of an 
   iteration, then a flag is set.  When the iteration is finished
   the program will terminate with the current answer. 
*/
  
  /* Just set this flag so we terminate after current iteration */
  gInterrupt = true;
}  /* signalHandler */

/**********************************************************************/
//  void setUpIntervalTimer( int secs ) {
//    /*  
//        If the -brief option is specified, then we set a timer for the
//        maximum number of seconds we will allow the program to run for.
//        */
//     struct itimerval value;

//     /* Zero or negative values turns time limits off.  */
//     if ( secs <= 0 )
//       return;

//     value.it_interval.tv_sec = secs;
//     value.it_interval.tv_usec = 0;

//     value.it_value.tv_sec = secs;
//     value.it_value.tv_usec = 0;

//     if ( setitimer( ITIMER_VIRTUAL, &value, NULL ) )
//        Abort( "Trouble in function call to setitimer().\n");

//     signal(SIGVTALRM, signalHandlerSIGVTALRM);

//  }  /* setUpIntervalTimer */
//  /**********************************************************************/
//  void setMemoryLimit( int mem_size_limit ) {
//  /* 
//       Sets the hard virtual memory size limit.  If process exceeds this
//       limit, then the SIGSEGV signal will be generated.  We also try to
//       catch this signal, but we are carefull not to assume that every
//       SIGSEGV is due to resource limitations. 
//  */
//    struct rlimit rlp;

//    /* Zero or negative values turns memory limits off. */
//    if ( mem_size_limit <= 0 )
//      return;

//  #ifdef DISABLE_MEMORY_LIMIT
//    return;

//  #else

//    /* Set the size */
//    rlp.rlim_cur = mem_size_limit;
//    rlp.rlim_max = mem_size_limit;

//  #ifdef SYSSOLARIS
//    setrlimit( RLIMIT_VMEM, &rlp );
//  #endif

//  #ifdef SYSLINUX
//    setrlimit( RLIMIT_DATA, &rlp );
//  #endif

//    /* Catch the signal */
//    signal(SIGSEGV, signalHandlerSIGSEGV);

//  #endif

//  }  /* setMemoryLimit */
//  /**********************************************************************/
void setUpCtrlC(  ) {
/*
  Registers the signal handler for the SIGINT signal which is
  generated by pressing CRTL-C.
*/
  signal(SIGINT, signalHandlerSIGINT );
  gInterrupt = false;

}  /* setUpCtrlC */
//  /**********************************************************************/
//  void setInterruptParamContext( PomdpSolveParams param ) {
//  /*
//    Sets the parameter context so that when interrupts are received we
//    can look there for information about where the soluton process
//    stoppped. 
//  */
//    gInterruptParamContext = param;
//  }  /* setInterruptParamContext */
//  /**********************************************************************/
  
